﻿using FinalPointSet.Model.Constant;
using FinalPointSet.Model.Model;
using FinalPointSet.View;
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Drawing;
using System.Linq;
using System.Runtime.InteropServices;
using System.Windows;
using System.Windows.Forms;
using System.Windows.Interop;
using System.Windows.Media.Animation;
using static FinalPointSet.Model.Util.ScreenUtil;
using Window = System.Windows.Window;
namespace FinalPointSet.Model.Util
{
    /// <summary>
    /// 窗体管理工具
    /// </summary>
    public class WindowUtil : SingletonBase<WindowUtil>
    {
        /// <summary>
        /// 窗体字典
        /// </summary>
        private Dictionary<Type, Window> Windows { get; set; } = new();
        /// <summary>
        /// 窗体句柄字典
        /// </summary>
        private Dictionary<Type, int> Handles { get; set; } = new();
        /// <summary>
        /// 记录窗体设计时大小的字典, 例如搜索窗口存在大小变化, 需要指定窗体的真实大小, 便于居中显示
        /// </summary>
        private Dictionary<Type, SizeF> WindowDesignSizes { get; set; } = new();

        public delegate void WindowShowHanlder(string windowName);
        public event WindowShowHanlder? OnWindowShow;
        /// <summary>
        /// 注册窗体
        /// </summary>
        /// <param name="window">窗体实体类</param>
        /// <param name="type">窗体的类型</param>
        public void Add(Window window, Type type)
        {
            if (!Windows.ContainsKey(type))
            {
                Windows.Add(type, window);
                Handles.Add(type, (int)new WindowInteropHelper(window).Handle);
                if (!WindowDesignSizes.ContainsKey(type))
                {
                    WindowDesignSizes.Add(type, new SizeF((float)window.Width, (float)window.Height));
                }
            }
        }

        /// <summary>
        /// 注册窗体
        /// </summary>
        /// <param name="window">窗体的实体类</param>
        /// <param name="type">窗体的类型</param>
        /// <param name="designSize">窗体设计时的大小</param>
        public void Add(Window window, Type type, SizeF designSize)
        {
            if (!Windows.ContainsKey(type))
            {
                Windows.Add(type, window);
                Handles.Add(type, (int)new WindowInteropHelper(window).Handle);
                if (!WindowDesignSizes.ContainsKey(type))
                {
                    WindowDesignSizes.Add(type, designSize);
                }
            }
        }

        /// <summary>
        /// 关闭窗体
        /// </summary>
        /// <param name="type">窗体类型</param>
        public void Close(Type type)
        {
            Windows.TryGetValue(type, out Window? w);
            if (w != null)
            {
                w.Close();
                Windows.Remove(type);
                Handles.Remove(type);
                WindowDesignSizes.Remove(type);
            }
        }

        /// <summary>
        /// 移除窗体
        /// </summary>
        /// <param name="type">窗体类型</param>
        public void Remove(Type type)
        {
            Windows.TryGetValue(type, out Window? w);
            if (w != null)
            {
                Windows.Remove(type);
                Handles.Remove(type);
                WindowDesignSizes.Remove(type);
            }
        }
        /// <summary>
        /// 关闭所有窗体
        /// </summary>
        public void CloseAll()
        {
            foreach (var item in Windows.ToList())
            {
                Window w = item.Value;
                w?.Close();
            }
            Windows?.Clear();
        }

        /// <summary>
        /// 获取窗体,若窗体没有创建,则创建
        /// </summary>
        /// <param name="type">窗体类型</param>
        /// <returns>窗体实例</returns>
        public Window Get(Type type)
        {
            Windows.TryGetValue(type, out Window? w);
            if (w != null)
            {
                return w;
            }
            else
            {
                if (Activator.CreateInstance(type) is Window window)
                {
                    Add(window, type);
                    return window;
                }
                else
                {
                    throw new Exception("无法获取窗体");
                }
            }
        }

        /// <summary>
        /// 显示窗体
        /// </summary>
        /// <param name="type">窗体类型</param>
        public void Show(Type type)
        {
            Window window = Get(type);
            SetVindowVisibility(window, Visibility.Visible);
            OnWindowShow?.Invoke(type.Name);
        }

        /// <summary>
        /// 显示窗体
        /// </summary>
        /// <param name="type">窗体类型</param>
        /// <param name="location">窗体类型出现的位置</param>
        public void Show(Type type, Location location, ScaleMode scaleMode = ScaleMode.None)
        {
            Window window = Get(type);
            if (scaleMode == ScaleMode.Auto)
            {
                //更新窗体分辨率和大小
                UpdateWindowDPI(type, null);
            }
            //更新窗体位置
            UpdateWindowLocation(type, location, scaleMode, null);

            //唤醒窗体
            window.Activate();
            // 设置可见性
            SetVindowVisibility(window, Visibility.Visible);
            OnWindowShow?.Invoke(type.Name);
        }

        /// <summary>
        /// 隐藏窗体
        /// </summary>
        /// <param name="type">窗体类型</param>
        public void Hide(Type type)
        {
            Window window = Get(type);
            SetVindowVisibility(window, Visibility.Hidden);
        }

        /// <summary>
        /// 最小化窗体
        /// </summary>
        /// <param name="type">窗体类型</param>
        public void Minimize(Type type)
        {
            Window? w = Get(type);
            if (w != null)
                w.WindowState = WindowState.Minimized;
        }

        /// <summary>
        /// 最大化窗体
        /// </summary>
        /// <param name="type">窗体类型</param>
        public void Maximized(Type type)
        {
            Window? w = Get(type);
            if (w == null) return;

            if (w.WindowState == WindowState.Normal)
            {
                w.WindowState = WindowState.Maximized;
            }
            else if (w.WindowState == WindowState.Maximized)
            {
                w.WindowState = WindowState.Normal;
            }
        }

        /// <summary>
        /// 设置窗体是否可见
        /// </summary>
        /// <param name="type">类型</param>
        /// <param name="v">是否可见</param>
        public void SetVindowVisibility(Window window, Visibility v)
        {
            if (window == null)
                return;
            //显示
            if (v == Visibility.Visible)
            {
                //仅对不可见的窗体进行显示操作
                if (window.Visibility != Visibility.Visible)
                {
                    window.Visibility = v;
                    WindowShowing(window);
                }
                //重新将窗体置于最前台
                IntPtr hWnd = new WindowInteropHelper(window).Handle;
                SetForegroundWindow(hWnd);
            }
            //隐藏
            else if (v == Visibility.Hidden)
            {
                WindowDisappear(window, () =>
                {
                    window.Visibility = Visibility.Hidden;
                }
                );
            }
        }

        /// <summary>
        /// 窗体消失后的回调函数
        /// </summary>
        public delegate void WindowDisappearHandler();
        /// <summary>
        /// 设置窗体消失
        /// </summary>
        /// <param name="window">待隐藏的窗体</param>
        /// <param name="callerBack">窗体隐藏动画完成后的回调函数</param>
        public static void WindowDisappear(Window window, WindowDisappearHandler callerBack)
        {
            Storyboard sb = new();
            DoubleAnimation anim = new()
            {
                From = 1,
                To = 0,
                Duration = new Duration(TimeSpan.FromSeconds(0.25)),
                EasingFunction = new QuadraticEase
                {
                    EasingMode = EasingMode.EaseOut
                }
            };
            Storyboard.SetTarget(anim, window);
            Storyboard.SetTargetProperty(anim, new PropertyPath("Opacity"));
            sb.Children.Add(anim);
            sb.Completed += (s, args) => callerBack.Invoke();
            sb.Begin();
        }
        /// <summary>
        /// 设置窗体显示
        /// </summary>
        /// <param name="window">待显示的窗体</param>
        public static void WindowShowing(Window window)
        {
            Storyboard sb = new();
            DoubleAnimation anim = new()
            {
                From = 0,
                To = 1,
                Duration = new Duration(TimeSpan.FromSeconds(0.25)),
                EasingFunction = new QuadraticEase
                {
                    EasingMode = EasingMode.EaseOut
                }
            };
            Storyboard.SetTarget(anim, window);
            Storyboard.SetTargetProperty(anim, new PropertyPath("Opacity"));
            sb.Children.Add(anim);
            sb.Begin();
        }


        public void SetWindowDesignSize(Type type, SizeF designSize)
        {
            WindowDesignSizes[type] = designSize;
        }

        private Dpi GetDPI(Type type)
        {
            Window window = Get(type);
            Window startWindow = Get(typeof(StartView));
            //优先获取当前窗体的DPI, 取不到则取StartView(后台窗体)的DPI
            Dpi? curWinDPI = ScreenUtil.GetDpi(window);
            Dpi? startWinDPI = ScreenUtil.GetDpi(startWindow);
            Dpi dpi = curWinDPI ?? startWinDPI ?? new Dpi(1, 1);
            return dpi;
        }

        /// <summary>
        /// 获取窗体的最大缩放比例
        /// </summary>
        /// <param name="type"></param>
        /// <param name="screen"></param>
        /// <param name="scaleMode"></param>
        /// <returns></returns>
        private double GetWindowMaxScale(Type type, Screen? screen = null)
        {
            Dpi dpi = GetDPI(type);
            //获取当前屏幕参数
            screen ??= GetPrimaryScreen();
            Rectangle bounds = screen.WorkingArea;
            Debug.Print($"当前屏幕参数, 全屏宽度: {bounds.Width}, 全屏高度: {bounds.Height}, DPI={dpi}");

            // 根据设计时的大小和实际大小, 进行缩放
            double scaleWidth = bounds.Width / Config.DesignScreenWidth / dpi.X;
            double scaleHeight = bounds.Height / Config.DesignScreenHeight / dpi.Y;

            //根据屏幕长高, 得到最大的缩放比例
            //再根据后台配置的最大缩放比例比较, 确定最终的缩放比例
            return Math.Max(Math.Min(scaleWidth, scaleHeight), Config.MainWindowMinScaleRate);
        }

        /// <summary>
        /// 跟新窗体分辨率
        /// </summary>
        /// <param name="type">窗体类型</param>
        /// <param name="screen">当前窗体所处的屏幕</param>
        /// <param name="scaleMode">缩放比例</param>
        public void UpdateWindowDPI(Type type, Screen? screen = null)
        {
            Window window = Get(type);
            //窗体设计时大小
            WindowDesignSizes.TryGetValue(type, out SizeF windowDesignSize);
            //最大缩放比例
            double maxScale = GetWindowMaxScale(type, screen);

            //更新窗体大小
            window.Width = maxScale * windowDesignSize.Width;
            window.Height = maxScale * windowDesignSize.Height;
            Debug.Print($"目标缩放比例:{maxScale}, 窗体大小: ({window.Width},{window.Height})");
        }

        public void UpdateWindowLocation(Type type, Location location, ScaleMode scaleMode, Screen? screen = null)
        {
            Window window = Get(type);
            //分辨率
            Dpi dpi = GetDPI(type);
            //获取当前屏幕参数
            Screen targetScreen = screen ?? GetPrimaryScreen();
            // 居中显示
            if (location == Location.Center)
            {
                if (scaleMode == ScaleMode.Auto)
                {
                    window.Left = (targetScreen.WorkingArea.Width / dpi.X - window.Width) / 2;
                    window.Top = (targetScreen.WorkingArea.Height / dpi.Y - window.Height) / 2;
                }
                else
                {
                    //窗体设计时大小
                    WindowDesignSizes.TryGetValue(type, out SizeF windowDesignSize);
                    window.Left = (targetScreen.WorkingArea.Width / dpi.X - windowDesignSize.Width) / 2;
                    window.Top = (targetScreen.WorkingArea.Height / dpi.Y - windowDesignSize.Height) / 2;
                }
            }
        }

        [DllImport("user32.dll")]
        [return: MarshalAs(UnmanagedType.Bool)]
        private static extern bool SetForegroundWindow(IntPtr hWnd);

        // Win32 API 结构
        [StructLayout(LayoutKind.Sequential)]
        public struct Win32Point
        {
            public int X;
            public int Y;
        }

        /// <summary>
        /// 窗体大小
        /// </summary>
        public class Size
        {
            /// <summary>
            /// 宽
            /// </summary>
            public double Width;
            /// <summary>
            /// 高
            /// </summary>
            public double Height;

            public Size(double width, double height)
            {
                Width = width;
                Height = height;
            }
        }
    }

    /// <summary>
    /// 窗体出现的位置
    /// </summary>
    public enum Location
    {
        /// <summary>
        /// 手动指定
        /// </summary>
        Manual,
        /// <summary>
        /// 居中
        /// </summary>
        Center
    }

    /// <summary>
    /// 缩放模式
    /// </summary>
    public enum ScaleMode
    {
        /// <summary>
        /// 自动根据分辨率进行调整
        /// </summary>
        Auto,
        /// <summary>
        /// 不缩放
        /// </summary>
        None
    }
}
